<#
    .AUTHOR
        cw50406@imcnam.ssmb.com  
    .GROUP
        RPA AA STE Support Team(dl.gt.cn.cstc.rpa.aa.ste@imcnam.ssmb.com)
    .VERSION
        2.0
    .Synopsis
        Remote VDI folder/files cleanup 
    .DESCRIPTION
        This script is used to clean up remote VDI(only belong to the script running domain) folder/files with different vdi and fid list
    .EXAMPLE
        .\cleanup.ps1 -vdi_source txt -inputFileSaved
        The script will read vdi and fid list from vdi_fid_list.txt in the same directory and then clean all the temp folder as default
    .EXAMPLE
        .\cleanup.ps1 -vdi_source db
        The script will read vdi and fid list from db depening on the script running computer domain and then clean all the temp folder as default
    .EXAMPLE
        .\cleanup.ps1 -vdi_source db -clean_path "C:\Temp\test"
        The script will read vdi and fid list from db depening on the script running computer domain and then clean all the files in "C:\Temp\test" folder
#>
[CmdletBinding()]param(
    [Parameter(Mandatory=$false)]
    [ValidateSet("db","txt","csv")]                           # vdi_source can only be in these 3 options 
    [string]$vdi_source="db",                                 # where the script will get the VDI-FID list
    [ValidateSet('prod','uat','dev','poc','lab')]
    [string]$vdi_env="uat",                                   # which env the script will take actions on the vdis 
    [string]$clean_path="C:\Users\#fid\AppData\Local\Temp",   # the path to be cleaned up, will be replaced to be the absolute path when running
    [string]$input_file="vdi_fid_list.txt",                   # used when $vdi_source is not 'db'
    [string]$logfile,                                         # the log file full path
    [switch]$inputFileSaved,                                  # whether the vdi-fid list file has already been saved
    [switch]$interactive                                      # true for asking user to enter vdi and fid list 
)	
$this_path = Split-Path -Parent ($MyInvocation.MyCommand.Definition)
. "$this_path\functions.ps1" #<-------------------------------- initilize parames, functions & .NET assembles
If( $PSBoundParameters.ContainsKey('logfile' ) ){
    $log_file=$logfile
}else{Write-Log Normal "--------------------------------START OF SCRIPT--------------------------------" $log_file}
Switch($vdi_source){
    "txt"{ #<-------------------------------- open vdi_fid_list.txt(create it if it not exists) and let user to enter the vdi list.
        $inputFile="$this_path\$input_file" ; If(!(test-path $inputFile )){new-item -ItemType File -Path $inputFile -force 1>$null}
        $inputlist = (get-content $inputFile)|?{$_ -imatch [regex]::Escape("$this_domain|$vdi_env|") -and $_.trim() -ne ""}|select -Unique|sort
        If( ($PSBoundParameters.ContainsKey('inputFileSaved') -and $inputlist.count -eq 0) -or !$inputFileSaved ){
            If( $interactive){
                clear-content $inputFile -force -ea 0
                Do{ # loop above action if the vdi list is empty 
                    write-host "Please save vdi(fid) list as below format in opened txt file each line as it's empty, please press 'Ctrl+C' if you want to quit:
                    
                    nam,MWDINTVM123296,aas0009
                    nam,MWDINTVM123297,aas0010"; notepad $inputFile; read-host " "
                    $inputlist = (get-content $inputFile)|?{$_ -imatch [regex]::Escape("$this_domain|$vdi_env|") -and $_.trim() -ne ""}|select -Unique|sort
                }While( $inputlist -eq $null  )
            }else{ # send emails
                write-log Error "Script stopped cause $inputFile is empty!" $log_file ; exit
            }
        }
    ;break}
    "db"{ # get this domain vdi and fid list from database
        $inputlist=@()
        $db_server=@{$this_domain=@{}}
        write-log Normal "Trying to get db server list from '$this_path\db_server_list.txt'" $log_file
        (cat "$this_path\db_server_list.txt") -imatch [regex]::Escape("$this_domain|$vdi_env|")|%{ # only get vdi from db that matches both domain and env 
            $key,$value=$_.split('|')[1,2]
            $db_server.$this_domain.$key=$value
        }
        Foreach( $e in $db_server.$this_domain.GetEnumerator()){ # only get this domain VDI-FID from DB
            $vdi_filter=Switch -regex (("$this_domain/{0}" -f $e.name)){ # get specified env VDI-FID from this domain DB
                "NAM/PROD"{'SW';break}
                "NAM/(UAT|DEV|POC|COB)"{'MW';break}
                "APAC/(PROD|UAT|COB)"{'APAC';break}
                "EUR/PROD"{'LD';break}
                "EUR/(UAT|COB)"{'FF';break}
            }
            $db_query=
                "select dc.HostName as VDI,du.UserName as FID
                FROM [ICGDB].[dbo].[Clients] dc,[ICGDB].[dbo].[Users] du
                where dc.UserId = du.Id and du.IsDeleted = 0
                and du.UserName like 'a%' and du.UserName <> 'aaadmin'"
            If( $e.name -imatch 'dev' ){
                $db_query+="`nand (dc.HostName like '$vdi_filter%' or dc.HostName like 'AWS%')"
            }else{
                $db_query+="`nand dc.HostName like '$vdi_filter%'"
            }
            write-log Normal "Starting to get VDI-FID list from $this_domain $($e.name.toupper()) DB" $log_file
            $this_db_pwd=[CredentialValidate.GetPassword]::ReturnDBPWD($this_domain,$e.name)
            If( ($connection=Connect-Sql -DBServer $e.value -DBPwd $this_db_pwd ) -ne $null ){
                If( ($db_detail=Execute-Sql -connection $connection -query $db_query) -ne $null ){
                    $db_detail|%{$inputlist+="$this_domain,{0},{1}" -f $_.VDI.tolower(),$_.FID.tolower()}
                }
                $connection.close()
                write-log Success "Done get VDI-FID list from $this_domain $($e.name.toupper()) DB" $log_file
            }else{Write-log Error "Failed to connect to DB server $($e.value) with user 'aa_dbread'!" $log_file}
        }
        $inputlist=$inputlist |?{$_ -imatch "^$this_domain" -and $_.trim() -ne ""}|select -Unique|sort
        $inputlist|out-file "$this_path\vdi_fid_list.txt" -Encoding utf8 -Force
    ;break}
    #"csv"{} to be updated for vdi source collection from CSV file
}
$clean_action={ # for parallel thread using 
    param($list,$cnt,$clean_params)
    #<-------------------------------------------- initilize functions & parames
    Function Write-Log(){
        [CmdletBinding()]param(
            [Parameter(Mandatory=$true)]
            [ValidateSet("Warning", "Error", "Success","Normal")]
            [string]$log_type,
            [string]$log_info,
            [string]$log_file
        )
        $cnt=0
        Do{
            Try{"{0:yyyy-MM-dd HH:mm:ss}--{1}: {2}" -f (get-date),$log_type,$log_info |Out-File -FilePath $log_file -Append -Encoding utf8 -Force -ea 1;break}Catch{sleep -Milliseconds 500 ;if(++$cnt -gt 10){write-error "wait too long(5s) to write log";break}
            }Finally{}
        }While(1)
    }
    $domain,$vdi,$fid=$list.split(',')
    $clean_path,$log_file=$clean_params
    $clean_path="\\$vdi\$clean_path".replace(":",'$').replace("#fid",$fid)
    write-host "Starting take action in $cnt-->$clean_path" ; write-host $log_file
    $file_info=''|select @{n="VDI";e={$vdi }}, @{n="FID";e={$fid}},@{n="CleanPath";e={$clean_path}},@{n="Size(MB)";e={'N/A' }}, @{n="Comments";e={'Success'}}
    If(Test-Connection $vdi -quiet -count 1 -ea 0){
        Try{
            If( test-path $clean_path -ea 0 ){
                try{
                    dir $clean_path -Recurse -ea 1|%{ $file_fullname=$_.fullname
                        Try{ 
                            del $file_fullname -Recurse -force -ea 1
                        }Catch{ # format error output to the logfile
                            If( ($del_error=$_.exception.Message) -inotmatch [regex]::Escape($file_fullname) ){
                                $del_error="$cnt-->{0}|$del_error" -f $file_fullname
                            }else{$del_error="$cnt-->$del_error"}
                            write-log Warning $del_error $log_file
                        }Finally{}
                    }
                }catch{ # format error output to the logfile
                    If( ($del_error=$_.exception.Message) -inotmatch [regex]::Escape($clean_path) ){
                        $del_error="$cnt-->$clean_path|$del_error"
                    }else{$del_error="$cnt-->$del_error"}
                    write-log Normal $_.exception.Message $log_file
                    write-log Warning $del_error $log_file
                }Finally{}
                if((gi $clean_path).PsIsContainer){new-item -ItemType Directory -path $clean_path -Force -ea 0|out-null}
                $objFSO = New-Object -ComObject Scripting.FileSystemObject
                $file_info.'Size(MB)'="{0:N2}" -f (($objFSO.GetFolder($clean_path).Size) / 1MB) # get folder size
                write-log Success "Done cleaning files and gettting folder size at $cnt-->$clean_path" $log_file
                write-host -ForegroundColor Yellow "Done processing job in $cnt-->$clean_path"
            }else{
                write-log Error "Not found $cnt-->$clean_path" $log_file
                $file_info.Comments="Folder/File not exists: $clean_path"
            }
        }Catch{
            write-log Error $_.exception.Message $log_file
            $file_info.Comments=$_.exception.Message
        }Finally{}
    }else{
        Write-Log Error "$cnt-$vdi is either offline or invalid name!" $log_file
        $file_info.Comments="$VDI is either offline or invalid name"
    }
    return $file_info
}
write-log Normal "There are total $($inputlist.count) folders in cleanup progress" $log_file
$result=Start-BulkThreads $inputlist $clean_action $clean_path,$log_file
$result|Export-Csv -Path $folder_size_file -UseCulture -NoTypeInformation -Encoding UTF8 -Force -ErrorAction Ignore
